#encoding=utf8
'''
Created on Nov 7, 2014

@author: jingyang <jingyang@smalltreemedia.com>
'''
from functools import partial

from django.contrib import admin
from django.utils import timezone
from django.contrib.admin import widgets
from django.contrib.admin.options import get_ul_class
from django.forms.models import modelformset_factory

import settings
from core.widgets import CustomForeignKeyRawIdWidget
from iap_info.models import IapInfo, Iap, IapType, PublicKey
from iap_info.forms import IapInfoForm
from utils import field, email_sending
from notification.models import Notice


class IapInline(admin.TabularInline):
    model = Iap
    can_delete = False
    extra = 1

    def get_formset(self, request, obj=None, **kwargs):
        if obj:
            self.extra = 0
            if obj.status == 'F':
                self.max_num = obj.iap_set.count()
        return super(IapInline, self).get_formset(request=request, obj=obj, **kwargs)

    def get_readonly_fields(self, request, obj=None):
        if obj and obj.status == 'F':
            return ('name', 'prd_id', 'type', 'price')
        return super(IapInline, self).get_readonly_fields(request=request, obj=obj)


class IapInfoAdmin(admin.ModelAdmin):
    list_display = ('request_id', 'get_app', 'get_editor_name', 'get_app_store',
        'get_apple_id', 'get_iap_list', 'status')
    list_filter = ('editor', 'app__app_store', 'status')
    list_per_page = 20
    search_fields = ('request_id', 'app__prj_code', 'app__old_prj_code',
        'app__app_id')
    inlines = [IapInline]
    exclude = ('request_id', 'status', 'editor')
    raw_id_fields = ('app',)
    form = IapInfoForm
    list_editable = ('status',)
    fieldsets = (
        (None, {
            'fields':
            (
            'app',
            'local_doc',
            'remote_doc',
            )
        }),
    )
    notice_content = '''
        <p>{0}</p>
        <p>Request ID: <a target='_blank' href='/admin/iap_info/iapinfo/{1}/'>{2}</a></p>
        '''

    class Media:
        js = ('base/js/custom_iap_admin.js', 'base/js/RelatedObjectLookups.js',)

    @field('Request Status', allow_tags=True, admin_order_field='status')
    def get_status(self, obj):
        if obj.status == 'N':
            cls = 'label-warning'
        elif obj.status == 'F':
            cls = 'label-success'
        elif obj.status == 'I':
            cls = 'label-important'
        elif obj.status == 'C':
            cls = ''
        else:
            cls = 'label-info'
        return "<span class='label %s' style='width: 40px;'><center>%s</center></span>" %\
            (cls, obj.get_status_display())

    @field('Editor', admin_order_field='editor')
    def get_editor_name(self, obj):
        return obj.editor.split('@')[0]

    @field('IAP Type / Price (USD) / Product ID / Name', allow_tags=True)
    def get_iap_list(self, obj, sp="<br />"):
        return sp.join(['%s / %s / %s / %s' % (i.type, i.price, i.prd_id, i.name) for i in obj.iap_set.all()])

    def get_list_display(self, request):
        if not request.user.is_superuser and\
        not request.user.groups.filter(name='Post-production Staff').exists():
            return ['get_status' if x == 'status' else x for x in self.list_display]
        return admin.ModelAdmin.get_list_display(self, request)

    def get_fieldsets(self, request, obj=None):
        if obj and obj.status == 'F':
            return ((None, {'fields':
            (
            'get_app',
            'local_doc',
            'remote_doc',
            )
        }),)
        if self.declared_fieldsets:
            return self.declared_fieldsets
        form = self.get_form(request, obj)
        fields = list(form.base_fields) + list(self.get_readonly_fields(request, obj))
        return [(None, {'fields': fields})]

    def get_readonly_fields(self, request, obj=None):
        if obj and obj.status == 'F':
            return ('app', 'get_app', 'local_doc', 'remote_doc')
        return self.readonly_fields

    @field('Apple ID', admin_order_field='app__app_id')
    def get_apple_id(self, obj):
        return obj.app.app_id

    @field('App Store', admin_order_field='app__app_store', allow_tags=True)
    def get_app_store(self, obj):
        return obj.app.get_app_store_icon()

    @field('App', allow_tags=True, admin_order_field='app__prj_code')
    def get_app(self, obj):
        return "<a href='%s%s/' target='_blank'>%s</a>" % ('/admin/app_info/app/',
            obj.app_id, obj.app)

    def get_changelist_formset(self, request, **kwargs):
        """
        Returns a FormSet class for use on the changelist page if list_editable
        is used.
        """
        if not request.user.is_superuser and\
        not request.user.groups.filter(name='Post-production Staff').exists():
            list_editable = ()
        else:
            list_editable = self.list_editable

        defaults = {
            "formfield_callback": partial(self.formfield_for_dbfield, request=request),
        }
        defaults.update(kwargs)
        return modelformset_factory(self.model,
            self.get_changelist_form(request), extra=0,
            fields=list_editable, **defaults)

    def formfield_for_foreignkey(self, db_field, request=None, **kwargs):
        db = kwargs.get('using')
        if db_field.name in self.raw_id_fields:
            kwargs['widget'] = CustomForeignKeyRawIdWidget(db_field.rel,
                                    self.admin_site, using=db)
        elif db_field.name in self.radio_fields:
            kwargs['widget'] = widgets.AdminRadioSelect(attrs={
                'class': get_ul_class(self.radio_fields[db_field.name]),
            })
            kwargs['empty_label'] = db_field.blank and _('None') or None

        return db_field.formfield(**kwargs)

    def get_actions(self, request):
        """
        remove delete action
        """
        actions = super(IapInfoAdmin, self).get_actions(request)
        if actions.get('delete_selected'):
            del actions['delete_selected']
        return actions

    def response_add(self, request, obj, post_url_continue=None):
        Notice.objects.notice_manager('New IAP Request',
            self.notice_content.format('', obj.pk, obj.request_id))
#        email_sending('New IAP Request.', 'Request ID: %s' % obj.request_id,
#            to=[i[1] for i in settings.MANAGERS])
        return admin.ModelAdmin.response_add(self, request, obj, post_url_continue=post_url_continue)

    def response_change(self, request, obj):
        if not request.user.is_superuser and\
        not request.user.groups.filter(name='Post-production Staff').exists():
            if obj.status == 'I':
                obj.status = 'N'
                obj.save()
                Notice.objects.notice_manager('IAP Request Updated',
                    self.notice_content.format('%s updated the IAP Request' %\
                        obj.editor.split('@')[0], obj.pk, obj.request_id))
#                email_sending('IAP Request Updated.', 'Request ID: %s <br /><br /> %s updated the IAP Request.' % (obj.request_id, obj.editor),
#                    to=[i[1] for i in settings.MANAGERS])
        return admin.ModelAdmin.response_change(self, request, obj)

    def save_model(self, request, obj, form, change):
        if not change:
            obj.editor = request.user.email
            current_year = timezone.now().year
            current_month = timezone.now().month
            current_day = timezone.now().day
            # no longer need make Public Key request in PTS
#            if obj.app.app_store == 'Google Play':
#                num = PublicKey.objects.get_latest_num()
#                PublicKey.objects.get_or_create(app=obj.app,
#                    defaults={'request_id': 'RPUK-%s%02i%02i%02i' % (current_year,
#                        current_month, current_day, num)})
            # no need to audit except iTunes App Store apps.
            if not obj.app.app_store == 'iTunes App Store':
                obj.status = 'F'
            latest = IapInfo.objects.filter(create_time__year=current_year,
                create_time__month=current_month, create_time__day=current_day).order_by('-request_id')[:1]
            if latest:
                latest = latest[0]
                num = int(latest.request_id[-2:]) + 1
            else:
                num = 1
            obj.request_id = 'RIAP-%s%s%s%s' % (current_year, '%02i' % current_month,
                '%02i' % current_day, '%02i' % num)
        obj.save()
        if 'status' in form.changed_data:
            if obj.status == 'F':
                Notice.objects.send_notice('IAP Request <strong>Successful</strong>',
                    self.notice_content.format("Your IAP Request has been <font color='red'>successfully registered</font>:",
                        obj.pk, obj.request_id), obj.editor)
#                email_sending('IAP Request Successful.', 'Request ID: %s <br /><br /> Your IAP Request has been successfully registered.' % obj.request_id,
#                    to=[obj.editor])
            elif obj.status == 'I':
                Notice.objects.send_notice('IAP Request <font color="red">Invalid</font>',
                    self.notice_content.format("Your IAP Request <font color='red'>needs update</font>:",
                        obj.pk, obj.request_id), obj.editor)
#                email_sending('IAP Request Invalid.', 'Request ID: %s <br /><br /> Your IAP Request needs update.' % obj.request_id,
#                    to=[obj.editor])
            elif obj.status == 'C':
                Notice.objects.send_notice('IAP Request <font color="red">Canceled</font>',
                    self.notice_content.format("Your IAP Request has been <font color='red'>canceled</font>:",
                        obj.pk, obj.request_id), obj.editor)
#                email_sending('IAP Request Canceled.', 'Request ID: %s <br /><br /> Your IAP Request has been canceled.' % obj.request_id,
#                    to=[obj.editor])


class IapTypeAdmin(admin.ModelAdmin):
    list_display = ('name', 'store', 'status')
    list_editable = ('status',)


class PublicKeyAdmin(admin.ModelAdmin):
    list_per_page = 20
    search_fields = ('app__prj_code', 'request_id')
    list_display = ('request_id', 'get_status', 'get_app', 'get_studio', 'get_pub_key',
        'get_editor', 'added_at')
    list_filter = ('status',)
    readonly_fields = ('request_id', 'app', 'get_app')
#    form = PublicKeyForm
    fieldsets = (
        (None, {
            'fields':
            (
            'request_id',
            'get_app',
            'pub_key',
            'added_at',
            'status',
            ),
        }),
    )

    class Media:
        js = ('base/js/custom_pubkey_admin.js',)

    @field('Fulfilled by', admin_order_field='editor')
    def get_editor(self, obj):
        return obj.editor.split('@')[0]

    @field('Public Key', allow_tags=True, admin_order_field='pub_key')
    def get_pub_key(self, obj):
        return obj.pub_key.replace(' ', '&nbsp;').replace('\n', '<br />')

    @field('Status', allow_tags=True, admin_order_field='status')
    def get_status(self, obj):
        return obj.get_status_mark()

    @field('App', allow_tags=True, admin_order_field='app__prj_code')
    def get_app(self, obj):
        return "<a href='%s%s/' target='_blank'>%s</a>" % ('/admin/app_info/app/',
            obj.app_id, obj.app)

    @field('Studio', admin_order_field='app__studio__pub_name')
    def get_studio(self, obj):
        return obj.app.studio

    def get_actions(self, request):
        actions = admin.ModelAdmin.get_actions(self, request)
        if actions.get('delete_selected'):
            del actions['delete_selected']
        return actions

    def has_add_permission(self, request):
        return False

    def save_model(self, request, obj, form, change):
        if 'pub_key' in form.changed_data:
            obj.app.pub_key = obj.pub_key or ''
            obj.app.save()
            obj.editor = request.user.email
            if not obj.added_at:
                obj.added_at = timezone.now()
        obj.save()


admin.site.register(IapInfo, IapInfoAdmin)
admin.site.register(IapType, IapTypeAdmin)
#admin.site.register(PublicKey, PublicKeyAdmin)
